package com.example.common.config;

import lombok.Data;
import lombok.EqualsAndHashCode;

import java.io.Serializable;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @Author Peng Yisheng
 * @Date 2024/11/8 11:05
 * @Description 核心规则类
 */
@Data
@EqualsAndHashCode(of = "id")
// TODO: 后续考虑改变模型，路径 匹配 API配置信息（美团Shepherd），替换Rule
public class Rule implements Comparable<Rule>, Serializable {

    private String id;  // 规则ID, 全局唯一

    private String name;  // 规则名称

    private String protocol;  // 协议

    private String serviceId;  // 后端服务ID

    private String prefix;  // 请求前缀

    private List<String> paths;  // 路径集合

    // TODO: 该字段用来控制路径匹配多条规则时，按优先级选一条，字段名应该改为 priority
    private Integer order;  // 规则排序 （对应场景：一个路径对应多条规则，然后只执行一条规则的情况？？）

    // 过滤器配置列表
    private Set<FilterConfig> filterConfigs = new HashSet<>();

    // 重试配置
    private RetryConfig retryConfig = new RetryConfig();

    // 限流配置列表
    private Set<FlowControlConfig> flowCtlConfigs = new HashSet<>();

    // 熔断配置列表
    private Set<HystrixConfig> hystrixConfigs = new HashSet<>();

    @Data
    @EqualsAndHashCode(of = "id")
    public static class FilterConfig {
        private String id;      // 过滤器唯一ID
        private String config;  // 过滤器规则描述，{"timeOut":500,"balance":random}
    }

    @Data
    public static class RetryConfig {
        private int times;  // 超时重试次数
    }

    @Data
    @EqualsAndHashCode(of = {"type", "value"})
    public static class FlowControlConfig {
        private String type;   // 限流类型-可以是path，也可能是IP或者服务
        private String value;  // 限流对象的值
        private String model;  // 限流模式-单机、分布式
        private String config; // 限流规则,是一个JSON
    }

    @Data
    @EqualsAndHashCode(of = "path")
    public static class HystrixConfig {
        private String path;                // 熔断降级路径
        private int timeoutInMilliseconds;  // 超时时间
        private int threadCoreSize;         // 核心线程数
        private String fallbackResponse;    // 降级响应
    }

    public FilterConfig getFilterConfig(String id) {
        for (FilterConfig config : filterConfigs) {
            if (config.getId().equalsIgnoreCase(id)) {
                return config;
            }
        }
        return null;
    }

    @Override
    public int compareTo(Rule o) {
        int orderCompare = Integer.compare(getOrder(), o.getOrder());
        if (orderCompare == 0) {
            return getId().compareTo(o.getId());
        }
        return orderCompare;
    }

}
